package nancal.mp.service.jenkins.publish

import nancal.mp.db.mongo.JenkinsLanguageEnum
import nancal.mp.db.mongo.mor
import nancal.mp.model.K8sDeployServiceModel
import nancal.mp.model.replaceVarModel
import nancal.mp.service.getDockerfileContent
import nancal.mp.service.jenkins.JenkinsPublishJob
import nancal.mp.service.jenkins.is_root_path
import nbcp.base.extend.AsString
import nbcp.base.extend.HasValue
import nbcp.base.extend.must
import nbcp.base.utils.UrlUtil
import nbcp.myoql.db.mongo.queryById


data class DevOpsDockerImageData(
    var language: JenkinsLanguageEnum = JenkinsLanguageEnum.Java,
    var languageVersion: String = "",
    var dockerBuildImage: String = "",
    var dockerImage: String = ""
)

fun JenkinsPublishJob.buildFiles(): List<FileContent> {
    if (this.task.buildInfo.isLib) {
        return listOf()
    }


    var list = mutableListOf<FileContent>()
    var def = K8sDeployServiceModel.load(this.task);

    var text = "";
    if (this.task.currentGitFolder.config.docker.id.HasValue) {
        text = mor.dev.userDockerfile.queryById(this.task.currentGitFolder.config.docker.id)
            .toEntity()
            .must()
            .elseThrow { "找不到 userDockerfile id:${this.task.currentGitFolder.config.docker.id}" }
            .dockerfile
    } else {
        text = this.task.language.getDockerfileContent(this.task.buildInfo.targetEnv)
    }

    if (text.HasValue) {
        text = text.replaceVarModel(def)
        list.add(FileContent("Dockerfile", text))
    }

    return list
}


fun JenkinsPublishJob.f_docker_build_before_check(): FunctionContent {
    if (this.task.language != JenkinsLanguageEnum.Java) {
        return FunctionContent("build-before-check", "")
    }

    var logFileName = "curl-result.txt"

    var p = "";
    if (this.task.buildInfo.msDeployEnvEnum != null) {
        p = " -P ${this.task.buildInfo.msDeployEnvEnum.toString()},public"
    }

    // 获取 nancal-feign,做到一个接口, 需要 openfeign 依赖!
    //改造 pom.xml , 查找 resources,并添加相应的文件
    return FunctionContent(
        "build-before-check",
        """
folder="＄1"
isApp=＄2

echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` "获取mvn依赖，并去除空行，去重"
echo "mvn dependency:tree -e -U -am ${p} -pl ＄folder | grep :compile | rev |  cut -d ' ' -f 1 | rev |  grep -v "^＄""
mvn dependency:tree -e -U -am ${p} -pl ＄folder | grep :compile | rev |  cut -d ' ' -f 1 | rev |  grep -v "^＄"> .ops.mvn.txt

if [ ＄? -ne 0 ]; then
    echo "mvn执行出错!"
    mvn dependency:tree -e -U -am ${p} -pl ＄folder
    exit 11
fi

if [ ＄isApp == true ]; then
    echo "检测 spring-boot-maven-plugin 插件 layout"
    echo "cat ＄folder/pom.xml | grep '<artifactId>spring-boot-maven-plugin</artifactId>' | wc -l"
    txt=＄(cat ＄folder/pom.xml | grep '<artifactId>spring-boot-maven-plugin</artifactId>' | wc -l)
    
    if [ ＄txt -ne 0 ]; then
        echo "cat ＄folder/pom.xml | grep '<layout>ZIP</layout>' | wc -l"
        txt=＄(cat ＄folder/pom.xml | grep '<layout>ZIP</layout>' | wc -l)
        if [ ＄txt -eq 0 ]; then
            echo "!!!!!!!!!!!!!!!!!!!!!!!!"
            echo "＄folder/pom.xml 中的 build.plugins.plugin 下 org.springframework.boot:spring-boot-maven-plugin.configuration.layout 必须为 ZIP!"
            echo "参考以下内容(使用了全角尖括号)："
            echo "＜plugin＞"
            echo "    ＜groupId＞org.springframework.boot＜/groupId＞"
            echo "    ＜artifactId＞spring-boot-maven-plugin＜/artifactId＞"
            echo "    ＜configuration＞"
            echo "        ＜layout＞ZIP＜/layout＞"
            echo "    ＜/configuration＞"
            echo "＜/plugin＞"
            echo "!!!!!!!!!!!!!!!!!!!!!!!!"
            exit 12
        fi
        
        echo "检测通过! spring-boot-maven-plugin layout=ZIP!"
    else
        echo "!!!!!!!!!!!!!!!!!!!!!!!!"
        echo "＄folder/pom.xml 必须存在 org.springframework.boot:spring-boot-maven-plugin !"
        echo "参考以下内容(使用了全角尖括号)："
        echo "＜plugin＞"
        echo "    ＜groupId＞org.springframework.boot＜/groupId＞"
        echo "    ＜artifactId＞spring-boot-maven-plugin＜/artifactId＞"
        echo "    ＜configuration＞"
        echo "        ＜layout＞ZIP＜/layout＞"
        echo "    ＜/configuration＞"
        echo "＜/plugin＞"
        echo "!!!!!!!!!!!!!!!!!!!!!!!!"
        exit 13
    fi



    echo "检测 openfeign 组件"
    echo "cat .ops.mvn.txt | grep openfeign | wc -l "
    txt=＄(cat .ops.mvn.txt | grep openfeign | wc -l)
    if [ ＄txt -ne 0 ]; then
        echo "存在 openfeign 组件,检测必须存在 spring-retry 组件"
        echo "cat .ops.mvn.txt | grep spring-retry  | wc -l"
        txt=＄(cat .ops.mvn.txt | grep spring-retry  | wc -l)
        if [ ＄txt -eq 0 ]; then
        
            echo "!!!!!!!!!!!!!!!!!!!!!!!!"
            echo "项目存在 openfeign 包，要求必须引入 org.springframework.retry:spring-retry 包, 请添加后再部署!"
            echo "参考以下内容(使用了全角尖括号)：："
            echo "＜dependency＞"
            echo "    ＜groupId＞org.springframework.retry＜/groupId＞"
            echo "    ＜artifactId＞spring-retry＜/artifactId＞"
            echo "＜/dependency＞"
            echo "!!!!!!!!!!!!!!!!!!!!!!!!"
            exit 14;
        fi
        
        
        echo "检测通过! 存在 openfeign,spring-retry"
    fi
fi

if [ "${appDeploySetting.snapshotVersionAction}" != "Ignore"]; then 
    snapshot=＄(cat .ops.mvn.txt | grep "SNAPSHOT" | rev |  cut -d ' ' -f 1 | rev | sort | uniq)
    line_count=＄(echo "＄snapshot" | awk 'END{print NR}')
    
    if [ ＄line_count -gt 0 ]; then
        echo "警告：发现 ＄line_count 个SNAPSHOT包！谨慎应用于生产环境！"
        echo "﹍﹎﹍﹎﹍﹎﹎﹎"
        echo "＄snapshot"
        echo "﹊﹉﹊﹉﹊﹉﹊﹊"
        
        if [ "${appDeploySetting.snapshotVersionAction}" != "Error"]; then
          exit 1;
        fi
    fi
    
    echo "cat .ops.mvn.txt | curl -X POST -o ${logFileName} -s -w %{http_code} --max-time 6 --retry 3 -H'Content-type:text/plain' --data-binary @- ${appDeploySetting.mpIntegrationApiUrl}/ops/cmd/mvn-dependency-check?admin-token=${UrlUtil.encodeURIComponent(appDeploySetting.adminToken)} "
    code=＄(cat .ops.mvn.txt | curl -X POST -o ${logFileName} -s -w %{http_code} --max-time 6 --retry 3 -H"Content-type:text/plain" --data-binary @- ${appDeploySetting.mpIntegrationApiUrl}/ops/cmd/mvn-dependency-check?admin-token=${UrlUtil.encodeURIComponent(appDeploySetting.adminToken)}) 
    
    if [ "＄code" == "000" ]; then
        echo "网络错误，请重试！"
        exit 3;
    elif [ "＄code" != "200" ]; then
        echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` "检查依赖接口错误!!! 返回: ＄code"
        show-file ${logFileName} 100
        exit 16
    fi
fi

"""
    )


    // find -type d -name resources | grep -v test | sort | head -1
}

fun JenkinsPublishJob.f_docker_pre_build(): FunctionContent {
    var list = mutableListOf<String>();
    if (this.is_root_path() == false) {
        list.add(
            """
if [ -f @folder@/pre_build.sh ]; then
    echo "重要消息!编译前钩子: @folder@/pre_build.sh"
    ${this.appDeploySetting.sudo} bash @folder@/pre_build.sh
fi
"""
        )
    }

    list.add(
        """
if [ -f ./pre_build.sh ]; then 
    echo "重要消息!编译前钩子: pre_build.sh" 
    ${this.appDeploySetting.sudo} bash ./pre_build.sh
fi
"""
    )

    return FunctionContent("pre_build", list.joinToString("\n"))
}

fun JenkinsPublishJob.f_docker_build(): FunctionContent {
    var logFileName = ".ops.build_log.txt"

    return FunctionContent(
        "build",
        """
if [ -f @folder@/build.sh ]; then 
    echo "重要消息!项目存在自定义编译脚本: @folder@/build.sh" 
    ${this.appDeploySetting.sudo} bash @folder@/build.sh
else
    @build_command@
    
    if [ ＄? -ne 0 ]; then
        echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '构建错误!!!'
        show-file ${logFileName} 500
      
        exit 1
    else
        echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '构建成功!'
        show-file ${logFileName} 200
    fi
fi
""".replace("@build_command@", this.get_build_command(logFileName))
    )
}


//fun JenkinsJob.f_docker_copy_nancal_feign(): FunctionContent {
//    var list = mutableListOf<String>();
//    if (this.task.language == JenkinsLanguageEnum.Java) {
//        var fillNancalFeign = sysDict.DevopsSettingEnum.fillNancalFeign.getDictValue();
//        if (fillNancalFeign.HasValue) {
//            list.add("""ls @folder@""")
//            list.add("""mv -n @folder@/nancal-feign-1.0.6.jar @folder@/lib-runtime/""")
//            list.add("""ls @folder@/lib-runtime""")
//        }
//    }
//
//
//    if (list.any() == false) {
//        list.add(":")
//    }
//    return FunctionContent("mvn-cp-nancal-feign", list.joinToString("\n"))
//}

fun JenkinsPublishJob.f_docker_post_build(): FunctionContent {
    var list = mutableListOf<String>();

    if (this.is_root_path() == false) {
        list.add(
            """
if [ -f @folder@/post_build.sh ]; then 
    echo "重要消息!编译后钩子: cd @folder@ && ${this.appDeploySetting.sudo} bash post_build.sh " 
    cd @folder@  &&  ${this.appDeploySetting.sudo} bash post_build.sh && echo "cd -" && cd -
fi
"""
        )
    }

    list.add(
        """
if [ -f ./post_build.sh ]; then 
    echo "重要消息!编译后钩子: ${this.appDeploySetting.sudo} post_build.sh" 
    ${this.appDeploySetting.sudo} bash ./post_build.sh
fi

"""
    )

    if (this.task.language == JenkinsLanguageEnum.Java) {
        list.add(
            """
echo "mkdir -p @folder@/target/lib && mkdir -p @folder@/lib-runtime"
mkdir -p @folder@/target/lib && mkdir -p @folder@/lib-runtime
        """
        )
    }

    list.add(
        """
echo "mkdir -p @folder@/res-runtime"
mkdir -p @folder@/res-runtime
"""
    )

    list.add(
        """
if [ -f "@folder@/web-server/install.sh" ]; then 
    echo "执行自定义WebServer： ${this.appDeploySetting.sudo} bash @folder@/web-server/install.sh"
    ${this.appDeploySetting.sudo} bash @folder@/web-server/install.sh
fi
        """
    )

    return FunctionContent("post_build", list.joinToString("\n"))
}

fun JenkinsPublishJob.s_prepare_build_function(): FileContent {
    var fileName = "code/.ops.build.fun.sh"
    var list = mutableListOf<String>()
    list.add(
        """#!/bin/bash
 
${f1_show_file()}
${f_docker_build_before_check()}
${f_docker_pre_build()}
${f_docker_build()}
${f_docker_post_build()}
    """
    )


    var appPath = this.task.buildInfo.buildFolder.trim('/');

    if (appPath.isEmpty()) {
        appPath = "."
    } else if (appPath == "./") {
        appPath = "."
    }


    return FileContent(
        fileName,
        list.joinToString("\n")
            .replace("""＄""", "$")
            .replace("@folder@", appPath)

    )
}

/**
 * 构建主任务
 */
fun JenkinsPublishJob.s_prepare_build_shell(): FileContent {
    var fileName = "code/.ops.build.sh"

    return FileContent(
        fileName,
        """
#!/bin/bash

cd /code && echo "文件夹切换到:`pwd`"

echo "执行构建" && echo "source ./.ops.build.fun.sh" &&  source ./.ops.build.fun.sh

echo "build-before-check '${this.task.buildInfo.buildFolder}' ${this.task.buildInfo.isApp}"
build-before-check  "${this.task.buildInfo.buildFolder}" ${this.task.buildInfo.isApp}

echo "执行 pre_build"  && pre_build && echo "执行 build" && build && echo "执行 post_build" && post_build  || ( "echo 构建失败！" ; exit 1 )
"""
    )
}

fun JenkinsPublishJob.get_build_command(logFileName: String): String {


    var cmd = "";
    var build_command = mutableListOf<String>();
    if (this.task.language == JenkinsLanguageEnum.Java) {
        var p = "";

        if (this.task.buildInfo.isApp) {
            if (this.task.buildInfo.msDeployEnvEnum != null) {
                p = " -P ${this.task.buildInfo.msDeployEnvEnum.toString()},public"
            }

            cmd = "mvn clean package -Dmaven.test.skip=true -e -U -am ${p} -pl ${
                this.task.buildInfo.buildFolder.AsString(
                    "."
                )
            }"


            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "编译打包：${cmd}" """
            build_command += cmd

            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "打包完成！" """
        } else {

            if (this.task.buildInfo.buildFolder
                    .replace(".", "")
                    .replace("/", "").HasValue
            ) {
                cmd = "mvn clean deploy -Dmaven.test.skip=true -e -U -P nexus -am -pl ${
                    this.task.buildInfo.buildFolder.AsString(
                        "."
                    )
                }"
            } else {
                cmd = "mvn clean deploy -Dmaven.test.skip=true -e -U -P nexus"
            }

            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "编译部署：${cmd}" """
            build_command += cmd
        }

    } else if (this.task.language.hasPackageJson()) {
        if (!this.is_root_path()) {
            build_command += """cd ${this.task.buildInfo.buildFolder} && echo "文件夹切换到:`pwd`" """
        }

        if (this.appDeploySetting.removeNpmLock) {
            cmd = "rm -rf package-lock.json yarn.lock"
            build_command += """echo "${cmd}" """
            build_command += cmd
        }

        // 由于还需要 yarn build ,所以 yarn install 千万不能加 --production
        cmd =
            "yarn install --registry ${this.appDeploySetting.nexusServer.nexusHttpUrl}/repository/npm-group"
        build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "安装依赖：${cmd}" """
        build_command += cmd

        if (this.task.buildInfo.isApp) {
            cmd = "yarn run ${this.task.currentGitFolder.buildScript.AsString("build")}"
            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "编译打包: ${cmd}" """
            build_command += cmd
            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "打包完成！" """
        } else {
            cmd =
                "yarn publish --registry ${this.appDeploySetting.nexusServer.nexusHttpUrl}/repository/npm-hosted"
            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "编译部署: ${cmd}" """
            build_command += cmd
            build_command += """echo -e `date "+%Y-%m-%d %H:%M:%S"` "部署完成！" """
        }

        if (!this.is_root_path()) {
            build_command += """cd - > /dev/null && echo "文件夹切换到:`pwd`" """
        }
    } else {
        throw RuntimeException("未实现编译的语言:${this.task.language}")
    }

    return build_command
//        .mapIndexed { index, s ->
//            if (index == build_command.size - 1) return@mapIndexed s;
//            if (s.trim().endsWith(";")) {
//                return@mapIndexed s;
//            }
//
//            return@mapIndexed s + " && ";
//        }
        .joinToString(" && ");
}

private fun getSafeValue(value: String?): String {
    if (value == null) return "";
    // remove 32-47
    // remove 58-64
    // remove 91-96
    // remove 123-126
    // - 是45
    val list = value.toCharArray().toMutableList();
    list.removeAll { (32..44).contains(it.code) }
    list.removeAll { (46..47).contains(it.code) }
    list.removeAll { (58..64).contains(it.code) }
    list.removeAll { (91..96).contains(it.code) }
    list.removeAll { (123..126).contains(it.code) }

    return list.joinToString("")
}


/**
if [ -f  code/${this.task.buildInfo.buildFolder}/docker.sh ]; then
echo "重要消息:项目存在 ${this.task.buildInfo.buildFolder}/docker.sh,移动到 code文件夹 同级执行"
mv code/${this.task.buildInfo.buildFolder}/docker.sh ./docker.sh
echo "docker.sh 内容:" && cat docker.sh && bash  ./docker.sh

if [ ＄? -ne 0 ]; then
echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` 'docker.sh 执行错误!!!'
exit 1
fi
fi
 */
/**
 * 多阶段构建
 */
fun JenkinsPublishJob.f2_docker_build(): FunctionContent {

    return FunctionContent(
        "docker-build", """
if [ "＄docker_image_version" == "" ]; then
    echo "!!!!!!!!!!!!!!!!!!!!!!!!"
    echo "docker_image_version 变量值为空!"
    echo "!!!!!!!!!!!!!!!!!!!!!!!!"
    exit 1
fi


echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` "构建命令(调试时执行 code/.ops.build.sh):"

echo "DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker build --progress=plain ${appDeploySetting.dockerBuildAddHostsParameters}  -t ${
            appDeploySetting.harborServer.getHarborImagePrefix(
                this.task.language
            )
        }${this.task.buildInfo.serviceName}:＄docker_image_version . "

${this.appDeploySetting.sudo} DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker build --progress=plain ${appDeploySetting.dockerBuildAddHostsParameters}  -t ${
            appDeploySetting.harborServer.getHarborImagePrefix(
                this.task.language
            )
        }${this.task.buildInfo.serviceName}:＄docker_image_version . 
        
if [ ＄? -ne 0 ]; then
    echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '构建镜像错误!!!'
    exit 1
else 
    echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '构建镜像成功!'
fi
"""
    )
}

fun JenkinsPublishJob.f2_docker_deploy(): FunctionContent {

    return FunctionContent(
        "docker-deploy", """
if [ "＄docker_image_version" == "" ]; then
    echo "!!!!!!!!!!!!!!!!!!!!!!!!"
    echo "docker_image_version 变量值为空!"
    echo "!!!!!!!!!!!!!!!!!!!!!!!!"
    exit 1
fi


echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` "构建命令(调试时执行 code/.ops.build.sh):"

echo "DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker build --progress=plain ${this.task.buildInfo.serviceName}:＄docker_image_version . "

${this.appDeploySetting.sudo} DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker build --progress=plain ${appDeploySetting.dockerBuildAddHostsParameters}  -t ${this.task.buildInfo.serviceName}:＄docker_image_version . 
        
if [ ＄? -ne 0 ]; then
    echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '构建镜像错误!!!'
    exit 1
else 
    echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '构建镜像成功!'
    ${this.appDeploySetting.sudo} docker rmi -f  ${this.task.buildInfo.serviceName}:＄docker_image_version
fi
"""
    )
}

/**
 * docker
 */
fun JenkinsPublishJob.f2_docker_mount_style_run(): FunctionContent {
    var image = "${appDeploySetting.harborServer.host}/tools/${this.task.language.toString().lowercase()}:"

    return FunctionContent(
        "docker-compile", """
echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` "构建命令:"

echo "${this.appDeploySetting.sudo}  docker run --rm --privileged=true ${appDeploySetting.dockerBuildAddHostsParameters} -v `pwd`/code:/code ${image} bash -c 'TZ="Asia/Shanghai" ; source /code/docker-build.sh; build'"

${this.appDeploySetting.sudo} docker run --rm --privileged=true ${appDeploySetting.dockerBuildAddHostsParameters} -v `pwd`/code:/code ${image} bash -c 'TZ="Asia/Shanghai" ; source /code/docker-build.sh; build'

if [ ＄? -ne 0 ]; then
    echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '编译错误!!!'
    exit 1
else 
    echo -e "\n"`date "+%Y-%m-%d %H:%M:%S"` '编译成功!'
fi

"""
    )
}

fun JenkinsPublishJob.f2_deploy_nginx(): FunctionContent {

    return FunctionContent(
        "deploy-nginx-conf", """

if [ -f code/${this.task.buildInfo.buildFolder}/nginx.conf ]; then
    echo "重要消息:项目存在 code/${this.task.buildInfo.buildFolder}/nginx.conf !"
    ＄is_root_path && mv -f code/${this.task.buildInfo.buildFolder}/nginx.conf code/nginx.conf
else
    mv -n ${nginxDefFileName} code/nginx.conf
fi
"""
    )
}